#include <iostream>
#include <unistd.h>
#include <pthread.h>
#include <vector>
#include <string>

#define NUM 5
pthread_mutex_t glock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t gcond = PTHREAD_COND_INITIALIZER;
int ticket = 1000;


// 等待是需要等，什么条件才会等呢？票数为0，等待之前，就要对资源的数量进行判定。
// 判定本身就是访问临界资源！，判断一定是在临界区内部的.
// 判定结果，也一定在临界资源内部。所以，条件不满足要休眠，一定是在临界区内休眠的!
// 证明一件事情：条件变量，可以允许线程等待
//                       可以允许一个线程唤醒在cond等待的其他线程时， 实现同步过程
void* threadrun(void* args)
{
    std::string name = static_cast<const char*>(args);
    while(true)
    {
        pthread_mutex_lock(&glock);
        //没有等待就会在一段时间内一个线程独占资源，造成线程饥饿
        //当一个线程获取锁后，它就会被阻塞在gcond的等待队列里，直到别的线程唤醒等待队列里的线程
        //这样也可以解释为什么有时会看到不同的输出顺序，可能当前线程持有锁后被阻塞，
        //但如果下一个唤醒的并不是它，它就不能执行自己的任务，而是别的被唤醒的线程执行任务

        //glock会在wait前被自动释放
        pthread_cond_wait(&gcond,&glock);
        std::cout << name << "对ticket进行自增" << ticket << std::endl;
        ticket++;
        pthread_mutex_unlock(&glock);
    }
}

int main()
{
    std::vector<pthread_t> threads;
    for(int i = 0; i<NUM; i++)
    {
        pthread_t tid;
        char* id = new char[64];
        snprintf(id,64,"thread-%d",i);
        int n = pthread_create(&tid, nullptr, threadrun, id);      
        if(n != 0)continue;
        threads.push_back(tid);
        sleep(1);
    }

    sleep(3);

    while(true)
    {
        // std::cout << "唤醒所有线程" << std::endl;
        // pthread_cond_broadcast(&gcond);//一次唤醒多个线程
        std::cout << "唤醒一个进程" << std::endl;
        pthread_cond_signal(&gcond);//一次唤醒一个线程
        sleep(1);
    }

    for(auto x : threads)
    {
        int n = pthread_join(x,nullptr);
        (void)n;
    }

    return 0;
}